package com.kkd.kkdapp.view.waveview;

import com.kkd.kkdapp.R;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

// y=Asin(ωx+φ)+k
class Wave extends View {


    public final int DEFAULT_ABOVE_WAVE_ALPHA = 256;
    public final int DEFAULT_BLOW_WAVE_ALPHA = 256;

    private final float X_SPACE = 5;
    private final double PI2 = 2 * Math.PI;

    private Path mAboveWavePath = new Path();
    private Path mBlowWavePath = new Path();

    private Paint mAboveWavePaint = new Paint();
    private Paint mBlowWavePaint = new Paint();

    private int mAboveWaveColor;
    private int mBlowWaveColor;

    private float mWaveMultiple;
    private float mWaveLength;
    private float mWaveHeight;
    private float mMaxRight;
    private float mWaveHz;
    private float mLevel;

    // wave animation
    private float mAboveOffset = 0.0f;
    private float mBlowOffset;
    private float mYOffset;

    private RefreshProgressRunnable mRefreshProgressRunnable;

    private int left, right, bottom;
    // ω
    private double omega;

    public Wave(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.waveViewStyle);
    }

    public Wave(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawPath(mBlowWavePath, mBlowWavePaint);
        canvas.drawPath(mAboveWavePath, mAboveWavePaint);
    }

    public void setAboveWaveColor(int aboveWaveColor) {
        this.mAboveWaveColor = aboveWaveColor;
    }

    public void setBlowWaveColor(int blowWaveColor) {
        this.mBlowWaveColor = blowWaveColor;

    }

    public Paint getAboveWavePaint() {
        return mAboveWavePaint;
    }

    public Paint getBlowWavePaint() {
        return mBlowWavePaint;
    }

    public void initializeWaveSize(float waveMultiple, float waveHeight, float waveHz) {
        mWaveMultiple = waveMultiple;
        mWaveHeight = waveHeight;
        mWaveHz = waveHz;
        mBlowOffset = mWaveHeight * (float) ((0.7f-Math.random()/2f));
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
        		ViewGroup.LayoutParams.MATCH_PARENT);
        setLayoutParams(params);
    }
    
    public void reSet(float waveMultiple, float waveHeight, float waveHz, float level) {
        mWaveMultiple = waveMultiple;
        mWaveHeight = waveHeight;
        mWaveHz = waveHz;
        mLevel = level;
        startWave();
    }

    public void initializePainters(int alpha1,int alpha2) {
        mAboveWavePaint.setColor(mAboveWaveColor);
        mAboveWavePaint.setStyle(Paint.Style.FILL);
        if(alpha1>0)
        	mAboveWavePaint.setAlpha(alpha1);
        mAboveWavePaint.setAntiAlias(true);

        mBlowWavePaint.setColor(mBlowWaveColor);
        mBlowWavePaint.setStyle(Paint.Style.FILL);
        if(alpha2>0)
        	mBlowWavePaint.setAlpha(alpha2);
        mBlowWavePaint.setAntiAlias(true);
    } 

    /**
     * calculate wave track
     */
    private void calculatePath() {
        mAboveWavePath.reset();
        mBlowWavePath.reset();
     
        getWaveOffset();

        float y;
        mAboveWavePath.moveTo(left, bottom);
        for (float x = 0; x <= mMaxRight; x += X_SPACE) {
            y = (float) (mWaveHeight* Math.sin(omega * x + mAboveOffset) +mYOffset);
            mAboveWavePath.lineTo(x, y);
        }
        mAboveWavePath.lineTo(right, bottom);

        mBlowWavePath.moveTo(left, bottom);
        for (float x = 0; x <= mMaxRight; x += X_SPACE) {
            y = (float) (mWaveHeight * Math.cos(omega * x + mBlowOffset) +mYOffset);
            mBlowWavePath.lineTo(x, y);
        }
        mBlowWavePath.lineTo(right, bottom);
    }

    @Override
    protected void onWindowVisibilityChanged(int visibility) {
        super.onWindowVisibilityChanged(visibility);
        if (View.GONE == visibility) {
            removeCallbacks(mRefreshProgressRunnable);
        } else {
            removeCallbacks(mRefreshProgressRunnable);
            mRefreshProgressRunnable = new RefreshProgressRunnable();
            post(mRefreshProgressRunnable);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
    }

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);
        if (hasWindowFocus) {
            if (mWaveLength == 0) {
                startWave();
            }
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (mWaveLength==0){
            startWave();
        }
    }

    private void startWave() {
        if (getWidth() != 0) {
            int width = getWidth();
            mWaveLength = width / mWaveMultiple;
            left = getLeft();
            right = getRight();
            bottom = getBottom() + 2;
            mYOffset = getHeight()-mWaveHeight-mLevel;
            mMaxRight = right + X_SPACE;
            omega = PI2 / mWaveLength;
        }
    }

    private void getWaveOffset() {
        if (mBlowOffset > Float.MAX_VALUE - 100) {
            mBlowOffset = 0;
        } else{
            mBlowOffset += mWaveHz;//(mWaveHz*(1-Math.random()/4));	
        }

        if (mAboveOffset > Float.MAX_VALUE - 100) {
            mAboveOffset = 0;
        } else{
            mAboveOffset += mWaveHz;//(mWaveHz*(1-Math.random()/4));
        }
    }

    private class RefreshProgressRunnable implements Runnable {
        public void run() {
            synchronized (Wave.this) {
                long start = System.currentTimeMillis();
                calculatePath();
                invalidate();
                long gap = 16 - (System.currentTimeMillis() - start);
                postDelayed(this, gap < 0 ? 0 : gap);
            }
        }
    }

}
